﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Webcam.Image.Filters
{
    /// <summary>
    /// Implements a fast box blur.
    /// By bluring horizontally then vertically
    /// </summary>
    public class BoxBlur : ImageAction
    {
        public BoxBlur(RGBImage src)
            : base(src)
        {

        }

        /// <summary>
        /// The width of the bluring box
        /// </summary>
        public int BoxWidth = 3;

        /// <summary>
        /// Process the box blur
        /// </summary>
        public override void Process()
        {
            output = new RGBImage(src.Width, src.Height);
            DoHorizBlur();
            DoVertBlur();
        }

        /// <summary>
        /// Do the horizontal blur
        /// </summary>
        void DoHorizBlur()
        {
            int w = src.Width;
            int h = src.Height;

            if (BoxWidth >= w)
                BoxWidth = w - 1;

            float mul = 1.0f / BoxWidth;

            int reach = BoxWidth/ 2;

            for (int y = 0; y < h; y++)
            {
                int tot = 0;
                for (int i = 0; i < reach; i++)
                    tot += src[i, y].GrayScale;

                for (int x = 0; x < w; x++)
                {
                    if (x > reach)
                        tot -= src[x-reach-1, y].GrayScale;
                    if (x + reach < w)
                        tot += src[x + reach, y].GrayScale;


                    float f = tot * mul;
                    if (x + reach >= w)
                        f = tot * (1.0f / (w - x + reach));
                    if (x < reach)
                        f = tot * (1.0f / (x + reach + 1));

                    if (f < 0)
                        f = 0;
                    if (f > 255)
                        f = 255;
                    byte val = (byte)f;
                    output[x, y] = new RGB(val);
                }
            }
        }

        /// <summary>
        /// Do the vertical blur
        /// </summary>
        void DoVertBlur()
        {
            int w = src.Width;
            int h = src.Height;

            if (BoxWidth >= w)
                BoxWidth = w - 1;

            float mul = 1.0f / BoxWidth;

            int reach = BoxWidth / 2;

            for (int x = 0; x < w; x++)
            {
                int tot = 0;
                for (int i = 0; i < reach; i++)
                    tot += src[x, i].GrayScale;

                for (int y = 0; y < h; y++)
                {
                    if (y > reach)
                        tot -= src[x, y - reach - 1].GrayScale;
                    if (y + reach < h)
                        tot += src[x, y + reach].GrayScale;


                    float f = tot * mul;
                    if (y + reach >= h)
                        f = tot * (1.0f / (h - y + reach));
                    if (y < reach)
                        f = tot * (1.0f / (y + reach + 1));

                    if (f < 0)
                        f = 0;
                    if (f > 255)
                        f = 255;
                    byte val = (byte)f;
                    output[x, y] = new RGB(val);
                }
            }
        }

    }
}
